package com.linshidream.intrachat.simplenio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Scanner;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * Created on 2025/7/24 18:25
 *
 * @author linshidream
 * @version 1.0.0
 * @description
 */

public class EventLoopClient {

    public static void main(String[] args) throws IOException {
        ScannerClient client = new ScannerClient();
        client.connect("localhost", 10010).start();

        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入你要发送的内容：");
        while (true) {
            String msg = scanner.nextLine();
            client.send(msg);
        }
    }

    public static class ScannerClient {

        private static final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1);

        // 客户端通道
        private SocketChannel channel;

        // 监听器
        private Selector selector;

        private int port;

        private String hostname;

        public ScannerClient connect(String hostname, int port) {
            this.port = port;
            this.hostname = hostname;
            return this;
        }

        /**
         * 开启客户端连接
         *
         * @throws IOException
         */
        public void start() throws IOException {
            channel = SocketChannel.open();
            channel.configureBlocking(false);
            channel.connect(new InetSocketAddress(hostname, port));

            selector = Selector.open();
            channel.register(selector, SelectionKey.OP_CONNECT);

            // 开启一个线程负责监听读事件
            SCHEDULER.schedule(() -> {
                try {
                    this.eventLoop();
                } catch (Exception e) {
                }
            }, 1, TimeUnit.MICROSECONDS);
        }

        /**
         * 客户端发送消息
         *
         * @param msg
         * @throws IOException
         */
        public void send(String msg) throws IOException {
            ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes(StandardCharsets.UTF_8));
            channel.write(buffer);
        }

        /**
         * 开始循环事件 支持循环输入
         *
         * @throws IOException
         */
        private void eventLoop() throws IOException {
            while (true) {
                // 阻塞直到有事件
                selector.select();

                Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    // 用完记得删除事件
                    iterator.remove();

                    if (key.isConnectable()) {
                        SocketChannel channel = (SocketChannel) key.channel();
                        System.out.println("客户端已连接到服务端：" + channel.getRemoteAddress());

                        // 建立连接后，再订阅读事件
                        if (channel.finishConnect()) {
                            channel.register(selector, SelectionKey.OP_READ);
                        }
                    }

                    // 当服务器响应成功产生可读事件
                    if (key.isReadable()) {
                        SocketChannel channel = (SocketChannel) key.channel();
                        ByteBuffer buffer = ByteBuffer.allocate(1024);
                        int len = channel.read(buffer);
                        if (len > 0) {
                            buffer.flip();
                            String resp = new String(buffer.array(), 0, len, StandardCharsets.UTF_8).trim();
                            System.out.println("客户端收到服务端回复：" + resp);
                            System.out.print("请再次输入你要发送的内容：");
                        }
                    }
                }
            }
        }
    }

}
